package org.fhm.zdte.client.cmd;

import org.fhm.substrate.annotation.BeanInitial;
import org.fhm.substrate.annotation.Component;
import org.fhm.substrate.annotation.Setup;
import org.fhm.zdte.common.ability.IGetResponseResult;
import org.fhm.zdte.common.constant.protocol.PacketType;
import org.fhm.zdte.common.constant.subcmd.RequestCmd;
import org.fhm.zdte.common.pojo.Request;
import org.fhm.zdte.common.pojo.Result;
import org.fhm.zdte.common.service.boot.AbstractStarter;
import org.fhm.zdte.common.standard.IReceiveMessageManager;
import org.fhm.zdte.common.standard.ISendMessageManager;

import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Request command processor.
 *
 * @author 谭波
 * @since 2023/12/26
 */
@Component("REQUEST")
public class RequestClientCmd extends AbstractClientCmd implements IGetResponseResult {

    private final Map<String, Result<String>> resultContainer = new ConcurrentHashMap<>();
    @Setup
    private Map<String, IReceiveMessageManager> iReceiveMessageManagerMap;
    @Setup
    private Map<String, ISendMessageManager> iSendMessageManagerMap;
    @Setup
    private AbstractStarter abstractStarter;

    @BeanInitial
    @SuppressWarnings("unchecked")
    private void beanInitial() {
        subPacketDataDealMap.get(PacketType.REQUEST.getName())
                .putConsumer(
                        RequestCmd.INITIAL,
                        (address, message) -> {
                            String contentTypeName = message.getContentType().getName();
                            ISendMessageManager iSendMessageManager =
                                    iSendMessageManagerMap.get(contentTypeName);
                            IReceiveMessageManager iReceiveMessageManager =
                                    iReceiveMessageManagerMap.get(contentTypeName);
                            if (abstractMessageMonitor.isAck(message)) {
                                iSendMessageManager.cancelInitialTaskAndSend(
                                        message.getMessageNumber(), address
                                );
                            } else {
                                iReceiveMessageManager.initial(message, address);
                            }
                        }
                )
                .putConsumer(
                        RequestCmd.SEND,
                        (address, message) -> {
                            IReceiveMessageManager iReceiveMessageManager =
                                    iReceiveMessageManagerMap.get(message.getContentType().getName());
                            if (abstractMessageMonitor.isSubMessage(message)) {
                                iReceiveMessageManager.addMessageToBuffer(message, address);
                                String messageNumber = message.getMessageNumber();
                                Request bean = iReceiveMessageManager.isCompleteAndGet(messageNumber);
                                if (Objects.nonNull(bean)) {
                                    if (Objects.isNull(bean.getInterfaceUrl())) {
                                        resultContainer.put(messageNumber, (Result<String>) bean);
                                        if (iThreadManager.notify(messageNumber))
                                            iReceiveMessageManager.sendCompleteScheduleAck(messageNumber, address);
                                    } else {
                                        iReceiveMessageManager.sendCompleteScheduleAck(messageNumber, address);
                                        String target = message.getFrom();
                                        Result<?> result = abstractStarter.dispatchServlet(target, bean);
                                        result.setInterfaceUrl(null);
                                        iSendMessageManagerMap.get(result.getContentType().getName()).initial(
                                                result,
                                                messageNumber,
                                                target
                                        );
                                    }
                                }
                            } else if (abstractMessageMonitor.isSubAckMessage(message))
                                iSendMessageManagerMap
                                        .get(message.getContentType().getName())
                                        .resendResponse(message, address);
                            else if (abstractMessageMonitor.isSuccessful(message))
                                iReceiveMessageManager.cancelCompleteAck(message.getMessageNumber());
                        }
                );
    }

    @Override
    public Result<String> getResponseResult(String messageNumber) {
        return resultContainer.remove(messageNumber);
    }
}
